﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OpenCvSharp;
using OpenCvSharp.WpfExtensions;

namespace OpenCvSharpExtension
{
    /// <summary>
    /// CameraCapture.xaml 的交互逻辑
    /// </summary>
    public partial class CameraCapture : UserControl
    {
        public CameraCapture()
        {
            InitializeComponent();
            this.Framerate = 24;
            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                CompositionTarget.Rendering += CompositionTarget_Rendering;
                this.Loaded += CameraCapture_Loaded;
                this.Unloaded += CameraCapture_Unloaded;
                cascadeClassifier = new CascadeClassifier("haarcascade_frontalface_default.xml");
                capture = new VideoCapture();
            }

        }

        private void CameraCapture_Unloaded(object sender, RoutedEventArgs e)
        {
            this.Close();
            capture.Dispose();
        }

        private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            render();
        }

        private readonly VideoCapture capture;
        private CascadeClassifier cascadeClassifier;

        private void CameraCapture_Loaded(object sender, RoutedEventArgs e)
        {
            if (AutoOpenWhenLoaded)
            {
                this.Open();
            }
        }

        public VideoCapture VideoCapture { get { return capture; } }

        /// <summary>
        /// 打开摄像头
        /// </summary>
        /// <returns></returns>
        public bool Open()
        {

            var result = capture.Open(this.CameraIndex, VideoCaptureAPIs.DSHOW);


            return result;
        }
        /// <summary>
        /// 关闭摄像头
        /// </summary>
        public void Close()
        {
            capture.Release();
        }


        /// <summary>
        /// 是否在控件加载完成后自动打开摄像头
        /// </summary>
        public bool AutoOpenWhenLoaded
        {
            get { return (bool)GetValue(AutoOpenWhenLoadedProperty); }
            set { SetValue(AutoOpenWhenLoadedProperty, value); }
        }

        public static readonly DependencyProperty AutoOpenWhenLoadedProperty =
            DependencyProperty.Register("AutoOpenWhenLoaded", typeof(bool), typeof(CameraCapture), new PropertyMetadata(false));



        /// <summary>
        /// 摄像头索引
        /// </summary>
        public int CameraIndex
        {
            get { return (int)GetValue(CameraIndexProperty); }
            set { SetValue(CameraIndexProperty, value); }
        }

        public static readonly DependencyProperty CameraIndexProperty =
            DependencyProperty.Register("CameraIndex", typeof(int), typeof(CameraCapture), new PropertyMetadata(0));



        /// <summary>
        /// 帧率
        /// </summary>
        public int Framerate
        {
            get { return (int)GetValue(FramerateProperty); }
            set { SetValue(FramerateProperty, value); }
        }

        public static readonly DependencyProperty FramerateProperty =
            DependencyProperty.Register("Framerate", typeof(int), typeof(CameraCapture), new PropertyMetadata(0, new PropertyChangedCallback((dp, e) =>
            {
                var cc = (CameraCapture)dp;
                var framerate = (int)e.NewValue;
                cc.interval = TimeSpan.FromSeconds(1) / framerate;
            })));


        /// <summary>
        /// 是否标记人脸
        /// </summary>
        public bool FaceFlag
        {
            get { return (bool)GetValue(FaceFlagProperty); }
            set { SetValue(FaceFlagProperty, value); }
        }

        public static readonly DependencyProperty FaceFlagProperty =
            DependencyProperty.Register("FaceFlag", typeof(bool), typeof(CameraCapture), new PropertyMetadata(false));


        /// <summary>
        /// 指定货获取图像的拉伸方式
        /// </summary>
        public Stretch Stretch
        {
            get { return (Stretch)GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); }
        }

        public static readonly DependencyProperty StretchProperty =
            DependencyProperty.Register("Stretch", typeof(Stretch), typeof(CameraCapture), new PropertyMetadata(Stretch.Fill));



        /// <summary>
        /// 获取或设置当前相机是否暂停画面
        /// </summary>
        public bool IsPaused
        {
            get { return (bool)GetValue(IsPausedProperty); }
            set { SetValue(IsPausedProperty, value); }
        }

        public static readonly DependencyProperty IsPausedProperty =
            DependencyProperty.Register("IsPaused", typeof(bool), typeof(CameraCapture), new PropertyMetadata(false));




        private WriteableBitmap take = null;
        private bool istake = false;
        /// <summary>
        /// 捕获下一帧画面
        /// </summary>
        /// <returns></returns>
        public async Task<WriteableBitmap> Capture()
        {
            istake = true;
            while (istake)
            {
                await Task.Delay(10);
            }
            return take;
        }


        private DateTime lastTime;
        private TimeSpan interval;
        private void render()
        {
            if (capture == null || capture.IsDisposed)
            {
                return;
            }
            if (IsPaused)
            {
                return;
            }
            var now = DateTime.Now;
            if (now - lastTime < interval)
            {
                return;
            }
            lastTime = now;
            using (var frameMat = new Mat())// capture.RetrieveMat())
            {
                capture.Read(frameMat);
                if (frameMat.Empty())
                {
                    take = null;
                    istake = false;
                    showImg(null);
                    return;
                }
                if (istake)
                {
                    take = WriteableBitmapConverter.ToWriteableBitmap(frameMat);
                    istake = false;
                }
                if (this.FaceFlag)
                {
                    var rects = cascadeClassifier.DetectMultiScale(frameMat, 1.1, 5, HaarDetectionTypes.ScaleImage, new OpenCvSharp.Size(30, 30));
                    System.Windows.Rect[] recs = null;
                    if (rects.Length > 0)
                    {
                        recs = new System.Windows.Rect[rects.Length];
                        int i = 0;
                        foreach (var item in rects)
                        {
                            recs[i++] = new System.Windows.Rect(item.X, item.Y, item.Width, item.Height);
                            Cv2.Rectangle(frameMat, item, Scalar.Green);
                        }
                    }
                    else
                    {
                        recs = new System.Windows.Rect[0];
                    }
                    this.OnFaceCaptured(recs);
                }
                showImg(frameMat);
            }
        }

        private WriteableBitmap bitmap;
        /// <summary>
        /// 获取当前位图
        /// </summary>
        public WriteableBitmap Bitmap
        {
            get => bitmap;
        }

        private void showImg(Mat frame)
        {
            if (frame == null || frame.Empty())
            {
                img.Source = null;
                return;
            }
            if (bitmap == null || bitmap.PixelWidth != frame.Width || bitmap.PixelHeight != frame.Height)
            {
                bitmap = frame.ToWriteableBitmap();
                this.OnGotBitmap();
            }
            else
            {
                bitmap.Blit(frame);
            }
            if (img.Source != bitmap)
            {
                img.Source = bitmap;
            }
        }


        public event RoutedEventHandler GotBitmap
        {
            add { AddHandler(GotBitmapEvent, value); }
            remove { RemoveHandler(GotBitmapEvent, value); }
        }

        public static readonly RoutedEvent GotBitmapEvent = EventManager.RegisterRoutedEvent(
        "GotBitmap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CameraCapture));

        protected virtual void OnGotBitmap()
        {
            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = CameraCapture.GotBitmapEvent;
            this.RaiseEvent(args);
        }


        /// <summary>
        /// 在每一帧触发，提供捕获到的人脸位置信息。
        /// </summary>
        public event RoutedEventHandler FaceCaptured
        {
            add { AddHandler(FaceCapturedEvent, value); }
            remove { RemoveHandler(FaceCapturedEvent, value); }
        }

        public static readonly RoutedEvent FaceCapturedEvent = EventManager.RegisterRoutedEvent(
        "FaceCaptured", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CameraCapture));

        protected virtual void OnFaceCaptured(System.Windows.Rect[] rects)
        {
            var args = new FaceCapturedRoutedEventArgs() { Rects = rects };
            args.RoutedEvent = CameraCapture.FaceCapturedEvent;
            this.RaiseEvent(args);
        }

    }

    public class FaceCapturedRoutedEventArgs : RoutedEventArgs
    {
        public System.Windows.Rect[] Rects { get; set; }
    }
}
